Helper.using('py.Figures', function (ns) {

    ns.Arc = function (params) {
        ns.Figure.call(this, params);
        ns.setType('Arc');

        this.getCenter = Helper.abstractMethod();
        this.getStart = Helper.abstractMethod();
        this.getEnd = Helper.abstractMethod();

        this.getRadius = function(){
            return ns.Point.distance(this.getCenter(),this.getStart());
        };

        this.getLength = function(){
            var angleMagnitude = this.getAngle().getMagnitude();
            return this.getRadius() * angleMagnitude.getRadian();
        };

        this.getAngle = function(){
            return new ns.Angle3Point({points:[this.getStart(),this.getCenter(),this.getEnd()]})
        };

        var visual = new Kinetic.Shape({
            drawFunc: function() {
                if((typeof this.center !== 'undefined') && (typeof this.radius !== 'undefined')
                    && (typeof this.startAngle !== 'undefined') && (typeof this.endAngle !== 'undefined')){
                    var context = this.getContext();
                    context.beginPath();
                    context.arc(this.center.x, this.center.y, this.radius, this.startAngle, this.endAngle, true);
                    context.stroke();
                }

            },
            strokeWidth:2,
            stroke:'black',
            draggable:false
        });

        this.drawFunc = function (viewPort) {
            this.update(viewPort);
            this.layer().draw();
        };

        this.update = function (viewPort) {
            visual.center = viewPort.getPixelPoint(this.getCenter().getPosition());
            visual.radius = viewPort.getPixelLength(this.getRadius());
            visual.startAngle = -(new ns.Vector2Point({head:this.getStart(),tail:this.getCenter()}))
                .getAngleFromOx().getRadian();
            visual.endAngle = -(new ns.Vector2Point({head:this.getEnd(),tail:this.getCenter()}))
                .getAngleFromOx().getRadian();
        };

        this.drawFunc = function(viewPort) {
            this.update(viewPort);
            this.layer().draw();
        };

        this.visual(visual);
    }

    ns.SemiCircle = function (params) {
        ns.Arc.call(this, params);
        ns.setType('SemiCircle');

        params = Helper.extend({
            points : []
        }, params);

        this.getCenter = function(){
            return new ns.MidPoint({ends:[params.points[0],params.points[1]]});
        };

        this.getStart = function(){
            return params.points[0];
        };

        this.getEnd = function(){
            return params.points[1];
        };

        this.getRadius = function(){
            return ns.Point.distance(this.getStart(),this.getEnd()) / 2;
        };

        this.getLength = function(){
            return this.getRadius() * Math.PI;
        };

        this.getAngle = function(){
            return new ns.AngleWithMagnitude({radian:Math.PI});
        };

        this.formed = function(){
            return params.points.length == 2;
        };

        this.setPoint = function(index, point){
            params.points[index] = point;
        };

        this.toString = function () {
            return 'SemiCircle: ';
        };
    }

    ns.CircularArc = function (params) {
        ns.Arc.call(this, params);
        ns.setType('CircularArc');

        var empty = new ns.PointXY;

        params = Helper.extend({
            center : empty,
            onCircle : empty,
            point : empty
        }, params);

        this.getCenter = function(){
            return params.center;
        };

        this.getStart = function(){
            return params.onCircle;
        };

        this.getEnd = function(){
            return params.point;
        };

        this.setCenter = function(point){
            params.center = point;
        };

        this.setOnCircle = function(point){
            params.onCircle = point;
        };

        this.setPoint = function(point){
            params.point = point;
        };

        this.getRadius = function(){
            return ns.Point.distance(this.getStart(),this.getCenter());
        };

        this.getLength = function(){
            //return this.getRadius() * Math.PI;
        };

        this.getAngle = function(){
            //return new ns.AngleWithMagnitude({radian:Math.PI});
        };

        this.formed = function(){
            return params.points.length == 2;
        };
    }
});
